home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 17 / CU Amiga Magazine's Super CD-ROM 17 (1997)(EMAP Images)(GB)[!][issue 1997-12].iso / CUCD / Programming / DiceSource / src / vsuck / vsuck.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-09-09  |  39.4 KB  |  1,296 lines

  1. /*
  2.  *    (c)Copyright 1992-1997 Obvious Implementations Corp.  Redistribution and
  3.  *    use is allowed under the terms of the DICE-LICENSE FILE,
  4.  *    DICE-LICENSE.TXT.
  5.  */
  6. /*
  7. **      $Id: vsuck.c,v 30.0 1994/06/10 18:09:35 dice Exp $
  8. **
  9. **        See what can be done with WIDEEXAMPLE
  10. **
  11. **        Start processing [$Marker] references
  12. **
  13. **      BUGS:
  14. **              Huge AslBase... line blows MAJOR_HEADING
  15. **
  16. **              strftime man page
  17. **        Notice <R> in tables
  18. **              Notice <197> 
  19. **              
  20. **
  21. **        !!!!!!!!!!!!!!!!!!!!!!!!!End-of-line blanks
  22. **
  23. **        Table mismatch in chap01.txt
  24. **
  25. **
  26. **              Flubs on:
  27. **                      Spaces at end of line
  28. **
  29. **              Flubs on:
  30. **                      @NAME = <TAB>KEYWORD<R>
  31. **                      <TAB>SUBTITUTION
  32. **
  33. **              Flubs on:
  34. **                      @OPTION = <TAB>-S0<R>
  35. **                      <TAB>-S1
  36. **
  37. **              Does not handle <TAB> in @INPUT, @OUTPUT, etc.
  38. **
  39. **              atexit example has NULL in it.
  40. **
  41. **      FEATURES:
  42. **              The final line of paragrah terminated with <R> will have
  43. **              leading spaces stripped:
  44. **                              #include <<stdio.h>><R>
  45. **                              #include <<cats.h>>
  46. **        This will not be fixed; VReturn puts a final <R> on the
  47. **        last line.
  48. **
  49. **      TODO:
  50. **              Tab optimize
  51. **              Check exact length of MAJOR_HEADING wrap.
  52. **
  53. */
  54. #define D(x)    
  55. #define D0(x)    
  56. #define D1(x)
  57. #define D2(x)   
  58. #define D3(x)   x;      // Warnings
  59. #define LINE_WIDTH      76      // So text won't wrap on 640 pixel wide screens
  60. #define MAX_PARAGRAPH   8000    // Yes... build that same limitation in.
  61.  
  62. #define MIN_INDENT      4
  63. #define BODY_INDENT     8
  64. #define TABLE_INDENT    1
  65. #define OPTION_INDENT   12
  66. #define D_INDENT        28      // Text after options, results
  67. #define EXAMPLE_INDENT  4       // Extra bytes past normal indent
  68.  
  69. #include <stdio.h>
  70. #include <stdlib.h>
  71. #include <string.h>
  72.  
  73. #define unless(x)       if(!(x))
  74. #define CR              13
  75. #define LF              10
  76. #define FF              12
  77. #define TAB             9
  78.  
  79.  
  80. /*******************************************************************************
  81. **      Column Stuff
  82. */
  83. #define DC1             0x11  // Standin for ',' in tables 0x40.
  84. #define DC2             0x12  // Standin for <R> in tables 0x23.
  85. #define MAXCOLUMNS      10
  86.  
  87. short   hasheader;      // Set if table has a header (thick line used)
  88.  
  89. struct ColumnInfo {     // Hold information about each of n columns
  90.  
  91.         // Prescan information
  92.         short maxfirst;   // Largest first word
  93.         short maxword;    // Largest word (make column no smaller!)
  94.         short maxline;    // Largest line (try to fit in this space)
  95.         short tablelines; // Number of rows (redundant in each column)
  96.         int   total;      // Total characters in this column (for ratio calc)
  97.         short flags;      //
  98.  
  99.         // Formatting information
  100.         short col_start;        // Start of actual text
  101.         short col_width;        // During format, location of vertical bar
  102.         short col_temp;
  103.         char *wrappointer;      // Current index, or zero if column is done
  104. };
  105.  
  106. /*******************************************************************************
  107. **      Globals
  108. */
  109. FILE    *outfile;                       // FP for final output
  110.  
  111. struct  ColumnInfo ColInfo[MAXCOLUMNS]; // Array of ColumnInfo
  112.  
  113. char    allspaces[] ="                                                                                ";
  114. char    allhash[]   ="################################################################################";
  115. char    alldash[]   ="--------------------------------------------------------------------------------";
  116. char    outbuf[LINE_WIDTH*2];           // Leave room for CR,LF,NULL, slop
  117. char    formatbuf[MAX_PARAGRAPH];       // Yes... build the same limitation in.
  118.  
  119. #define INDENT_INVALID  0
  120. #define INDENT_OPTION   1               // *must* be followed by text
  121. #define INDENT_VFORMAT  2               // *may*  be followed by text
  122. char    indenttext[LINE_WIDTH*2];       // For text in the left margin
  123. char    indenttextvalid=0;              //      -option  This is an option
  124.  
  125. int     bodyindent      =BODY_INDENT;
  126. int     optionindent    =OPTION_INDENT;
  127. int     indent          =BODY_INDENT;
  128.  
  129. char          *startinp;                // Start of input
  130. register char *inp;                     // Walking input pointer
  131.  
  132. int     enum_val=1;                     // For @ENUM auto-counting
  133.  
  134.  
  135.  
  136. /*******************************************************************************
  137. **      Prototypes
  138. */
  139. void ProcessFile();
  140. void putn(char *string,char terminator);
  141. void FormatParagraph(int slen,char *prestring1,char *prestring2);
  142. int  CollectParagraph(void);
  143. int CollectTable(void);
  144. FilterSpaces(register char *leading);
  145. FilterCR(register char *leading);
  146.  
  147.  
  148. /******************************************************************************/
  149. main(int argc,char *argv[])
  150. {
  151. FILE    *infile;
  152. long     insize;
  153.  
  154.     if (argc != 3 || ( argc == 2  &&  *argv[1]=='?' ) ) {
  155.         printf("VSuck <infile> <outfile>\n");
  156.         printf("; Format a Ventura document as text.  Like NROFF\n");
  157.         exit(5);
  158.         }
  159.  
  160.     unless( infile=fopen(argv[1],"r" ) ) {
  161.         printf("Error: Can't read \"%s\"\n",argv[1]);
  162.         exit(10);
  163.         }
  164.     unless( outfile=fopen(argv[2],"w" ) ) {
  165.         printf("Error: Can't write to \"%s\"\n",argv[2]);
  166.         fclose(infile);
  167.         exit(10);
  168.         }
  169.  
  170.     inp=0;
  171.     fseek(infile,0,2);
  172.     if( insize=ftell(infile) )
  173.         {
  174.         fseek(infile,0,0);
  175.         if ( inp=malloc( insize+4 ) )
  176.             {
  177.             if ( insize==fread( inp,1,insize,infile ) )
  178.                 {
  179.                 inp[insize]  =0;        // Lots of space for sloppy code
  180.                 inp[insize+1]=0;        // to read past without harm
  181.                 inp[insize+2]=0;
  182.                 inp[insize+3]=0;
  183.                 }
  184.                 else
  185.                 {
  186.                 printf("Error: Can't read \"%s\"\n",argv[1]);
  187.                 free( inp );
  188.                 inp=0;
  189.                 }
  190.             }
  191.             else
  192.             {
  193.             printf("Error: Out of memory (%ld bytes required)\n",insize+2);
  194.             }
  195.         }
  196.  
  197.     startinp=inp;
  198.     if( inp ) {
  199.         FilterCR(inp);  // Delete all CR
  200.         ProcessFile();
  201.         free( startinp );
  202.         }
  203.  
  204.     fclose( infile );
  205.     fclose( outfile );
  206.     printf("Exiting. Remember to tab & space optimize output!!!!\n");
  207.     printf("         Remember to tab & space optimize output!!!! Have a nice day.\n");
  208. }
  209.  
  210.  
  211. /*******************************************************************************
  212. **      Misc utility functions
  213. */
  214. //      Like puts, put terminates at given character
  215. void putn(char *string,char terminator)
  216. {
  217. char *temp;
  218.  
  219.         temp=strchr(string,terminator);
  220.         if (temp)
  221.             fwrite(string,temp-string+1,1,stdout);
  222. }
  223.  
  224. //      Like strnlen, but counts to given character
  225. int strlenc(s,c)
  226. const char *s;
  227. char    c;
  228. {
  229.     const char *b = s;
  230.  
  231.     while (*s != c)
  232.     ++s;
  233.  
  234.     return(s - b);
  235. }
  236.  
  237. //      Given start and current, count newlines to come up with a line number
  238. //              !!! TODO: Add cache
  239. int ErrorLine(char *start, char *current)
  240. {
  241. int     linenum =1;
  242.  
  243.         for(;start < current; start++)
  244.                 if ( *start==LF )
  245.                         linenum++;
  246.  
  247.         return(linenum);
  248. }
  249.  
  250. // Do in-place removal of spaces
  251. FilterSpaces(register char *leading)
  252. {
  253. register char *trailing=leading;
  254. register char c;
  255.  
  256.         while( c=*leading++ )
  257.                 {
  258.                 if (c != ' ')
  259.                         *trailing++=c;
  260.                 }
  261.         *trailing=0;
  262. }
  263.  
  264. // Do in-place removal of CR
  265. FilterCR(register char *leading)
  266. {
  267. register char *trailing=leading;
  268. register char c;
  269.  
  270.         while( c=*leading++ )
  271.                 {
  272.                 if (c != CR)
  273.                         *trailing++=c;
  274.                 }
  275.         *trailing=0;
  276.         trailing++;
  277.         *trailing=0;
  278.         trailing++;
  279.         *trailing=0;
  280.         trailing++;
  281.         *trailing=0;
  282.         trailing++;
  283. }
  284.  
  285. /*******************************************************************************
  286. **      @ Functions
  287. */
  288.  
  289. char *VFORMAT()
  290. {
  291. int     len=0;
  292.  
  293.         len=CollectParagraph();
  294.  
  295.         unless(len && (len < LINE_WIDTH) ) {
  296.             printf("Warning: @INPUTV/RESULTV no text/too long (%d)\n",ErrorLine(startinp,inp));
  297.             return(0);
  298.             }
  299.         D(printf("@VFORMAT: inp=%lx,len=%d,indent=%d,string=%s\n",inp,len,indent,formatbuf));
  300.  
  301.         /* Treat VFORMAT like an option.  New line if it won't fit properly.
  302.         */
  303.         if ( len+3 > (D_INDENT-indent-1))
  304.             {
  305.             memcpy(&outbuf[indent],&formatbuf[0],len+1);  // Copy null
  306.             fprintf(outfile,"%s\n",outbuf);
  307.             }
  308.         else{
  309.             memcpy(&outbuf[indent],&formatbuf[0],len);
  310.             strcpy(indenttext,outbuf);      // Copy string + lots of spaces
  311.             indenttextvalid=INDENT_VFORMAT;
  312.             }
  313.  
  314.         return(0);
  315. }
  316.  
  317.  
  318. char *OPTION()
  319. {
  320. int     len=0;
  321.  
  322.         len=CollectParagraph();
  323.  
  324.         unless(len && (len < LINE_WIDTH) ) {
  325.             printf("Warning: @OPTION no text/too long (%d)\n",ErrorLine(startinp,inp));
  326.             return(0);
  327.             }
  328.  
  329.         D1(printf("@OPTION: inp=%lx,len=%d,indent=%d,string=%s\n",inp,len,indent,formatbuf));
  330.  
  331.         if ( formatbuf[0] == TAB )
  332.                 printf("Warning: TAB before OPTION text (%d)\n", ErrorLine(startinp,inp));
  333.  
  334.         /*
  335.         ** If the option fits in the indent area, right justify it.
  336.         ** else insert a line with just the option on it.
  337.         **
  338.         */
  339.         if ( len+3 > indent)
  340.             {
  341.             memcpy(&outbuf[1]           ,&formatbuf[0],len+1);  // Copy null
  342.             fprintf(outfile,"%s\n",outbuf);
  343.             }
  344.         else{
  345.             memcpy(&outbuf[indent-len-2],&formatbuf[0],len);
  346.             strcpy(indenttext,outbuf);      // Copy string + lots of spaces
  347.             indenttextvalid=INDENT_OPTION;
  348.             }
  349.  
  350.         return(0);
  351. }
  352.  
  353. char *MAJOR_HEADING()
  354. {
  355. int     len;
  356. char    *description=0;    // Second part of new style MAJOR_HEADING lines
  357.             // @MAJOR_HEADING = wc - Count words in file
  358.  
  359.         CollectParagraph();
  360.  
  361.     if ( description = strchr(formatbuf,'-') ) {
  362.         if ( (description[-1] != ' ') || (description[1] != ' ') )
  363.                 printf("Warning: Non-standard dashed MAJOR_HEADING (%d)\n",ErrorLine(startinp,inp));
  364.         description[-1] = 0;
  365.         description += 2;
  366.         }
  367.  
  368.         FilterSpaces(formatbuf);
  369.         len=strlen(formatbuf);
  370.  
  371.         if ( 6+5+len+len+1 > LINE_WIDTH)
  372.                 {
  373.                 D3(printf("Warning: MAJOR_HEADING very long (%d bytes) (%d)\n",len , ErrorLine(startinp,inp)));
  374.                 fprintf(outfile," dice/%s\n\n",formatbuf);
  375.                 }
  376.         else    {
  377.                 memcpy(outbuf  ," dice/",6);
  378.                 memcpy(outbuf+6,formatbuf,len);
  379.                 memcpy(outbuf+LINE_WIDTH-len-5+1,"dice/",5);
  380.                 memcpy(outbuf+LINE_WIDTH-len  +1,formatbuf,len);
  381.                 outbuf[LINE_WIDTH+1]=0;
  382.                 fprintf(outfile,"%s\n\n",outbuf);
  383.                 }
  384.  
  385.     if ( description ) {
  386.         fprintf(outfile,"",outfile);
  387.         fwrite(allspaces,MIN_INDENT,1,outfile);
  388.             fprintf(outfile,"FUNCTION\n");
  389.         fwrite(allspaces,BODY_INDENT,1,outfile);
  390.         fprintf(outfile,"%s\n\n",description);
  391.     }
  392. }
  393.  
  394. char *BEGINNER()
  395. {
  396.         FormatParagraph(CollectParagraph(),":: ",":: ");
  397. }
  398.  
  399. char *NOTE()
  400. {
  401.         FormatParagraph(CollectParagraph(),"|| ","|| ");
  402. }
  403.  
  404. char *WARNING()
  405. {
  406.         FormatParagraph(CollectParagraph(),"## ","## ");
  407. }
  408.  
  409. char *BULLET()
  410. {
  411.         FormatParagraph(CollectParagraph(),"o ","  ");
  412. }
  413.  
  414. char *GENERIC()
  415. {
  416.         FormatParagraph(CollectParagraph(),"","");
  417. }
  418.  
  419. char *EXAMPLE()
  420. {
  421.         // indent += EXAMPLE_INDENT;
  422.         FormatParagraph(CollectParagraph(),"","");
  423.         // indent -= EXAMPLE_INDENT;
  424. }
  425.  
  426. char *ENUM()
  427. {
  428. char    temp[16];
  429.  
  430.         sprintf(temp,"%d) ",enum_val);
  431.         enum_val++;
  432.         FormatParagraph(CollectParagraph(),temp,"   ");
  433. }
  434.  
  435. char *CATEGORY()
  436. {
  437.         fwrite(allspaces,MIN_INDENT,1,outfile);
  438.         fprintf(outfile,"NAME\n");
  439.         FormatParagraph(CollectParagraph(),"","");
  440. }
  441.  
  442. char *NAME()
  443. {
  444. int      len;
  445. char    *temp;
  446.  
  447.         len=CollectParagraph();
  448.         temp=formatbuf;
  449.         if (len)
  450.             if (formatbuf[0]==TAB)      // TAB means right justify
  451.                 temp++;
  452.         strcpy(&outbuf[MIN_INDENT],temp);
  453.         fprintf(outfile,"%s\n",outbuf);
  454. }
  455.  
  456. char *MINOR_HEADING()
  457. {
  458. int      len;
  459. char    *temp;
  460.  
  461.         len=CollectParagraph();
  462.         temp=formatbuf;
  463.  
  464.         if (len)
  465.             if (formatbuf[0]==TAB) {    // TAB means right justify
  466.                 temp++;
  467.                 len--;
  468.                 printf("Warning: TAB in MINOR_HEADING (%d)\n", ErrorLine(startinp,inp));
  469.             }
  470.         if (len) {
  471.             strcpy(&outbuf[MIN_INDENT],temp);
  472.             fprintf(outfile,"%s\n",outbuf);
  473.             memcpy(&outbuf[MIN_INDENT],alldash,len);
  474.             outbuf[MIN_INDENT+len]=0;
  475.             fprintf(outfile,"%s\n",outbuf);
  476.         }
  477. }
  478.  
  479. char *Z_TBL_BEG()
  480. {
  481.  
  482.         // Skip @Z_TBL_BEG.  Turns out, we don't use any information from it!
  483.         while( *inp && !(inp[0]==LF && inp[1]==LF) )
  484.             inp++;
  485.  
  486.         // Strip formatting
  487.         CollectTable();
  488.         D1(printf("@TABLE: inp=%lx,string=\n%s\n",inp,formatbuf));
  489.  
  490.         // Collect statistics, then Write to output
  491.         WriteTable(PrescanTable(formatbuf),formatbuf);
  492. }
  493.  
  494.  
  495. /*
  496. **      Figure out how to format the table
  497. */
  498. #define MAGIC_SMALLCOLUMN 11     // Treat small first columns preferentially
  499.  
  500. int ThinkDeeply(int columns)
  501. {
  502. int     leftmargin;
  503. int     i,j,whatif,whatif2;
  504. short   columnspace;            // Space available to assign widths
  505.  
  506.     columnspace = LINE_WIDTH-TABLE_INDENT-((columns-1)*3);
  507.     D1(printf("ThinkDeeply: Assignable columns = %d\n",columnspace));
  508.  
  509.     /*
  510.     **  Determine if table is impossible, and clear out col_start/col_width
  511.     */
  512.     whatif=0;
  513.     for ( i=0; i < columns; i++) {
  514.         whatif += (ColInfo[i].maxword);
  515.         ColInfo[i].col_start   = 0;
  516.         ColInfo[i].col_width   = 0;
  517.         ColInfo[i].col_temp    = 0;
  518.         ColInfo[i].wrappointer = 0;
  519.     }
  520.     if (whatif > columnspace ) {
  521.         printf("Error: Impossible table; words too large (%d)\n",ErrorLine(startinp,inp));
  522.         return(0);
  523.     }
  524.  
  525.     /*
  526.     **  Now try to fit all text on a single line
  527.     */
  528.     whatif=0;
  529.     for ( i=0; i < columns; i++)
  530.         whatif += (ColInfo[i].maxline);
  531.     D1(printf("Total maximum length (whatif)=%d\n",whatif));
  532.  
  533.     /*
  534.     **  Ideal Situation.  Everything fits on one line.  Center the column
  535.     */
  536.     if (whatif < columnspace ) {
  537.         leftmargin = ((columnspace-whatif) / 2) + TABLE_INDENT;
  538.         j = leftmargin;
  539.         for ( i=0; i< columns; i++) {
  540.             ColInfo[i].col_start = j;
  541.             ColInfo[i].col_width = ColInfo[i].maxline;
  542.             j = j + 3 + ColInfo[i].maxline;
  543.         }
  544.         D1(printf("ThinkDeeply chooses: Single line\n"));
  545.         return(leftmargin);
  546.     }
  547.  
  548.     /*
  549.     **  Next, fit small first column with single large second column
  550.     */
  551.     if ( columns == 2 && ColInfo[0].maxline < MAGIC_SMALLCOLUMN ) {
  552.         ColInfo[0].col_start = TABLE_INDENT;
  553.         ColInfo[0].col_width = ColInfo[0].maxline;
  554.         ColInfo[1].col_start = ColInfo[0].maxline+TABLE_INDENT+3;
  555.         ColInfo[1].col_width = LINE_WIDTH-TABLE_INDENT-3-ColInfo[0].maxline;
  556.         D1(printf("ThinkDeeply chooses: Small first column\n"));
  557.         return(TABLE_INDENT);
  558.     }
  559.  
  560.     /*
  561.     **  No tricks worked :-(.  Assign widths based on weight of text.  The
  562.     **  more text in a column, the wider.  No column may be smaller than
  563.     **  the largest word.
  564.     **
  565.     */
  566.     // First, add up total of all text.
  567.     whatif = 0;
  568.     for ( i=0; i < columns; i++) {
  569.         whatif += ColInfo[i].total;
  570.     }
  571.     D1(printf("ThinkDeeply brute force: %d total characters\n",whatif));
  572.  
  573.     // Second, calculate ratios.  More text means larger column.
  574.     whatif  *= 1000;                    // Total chars
  575.     whatif2  = whatif / columnspace;    // Space avail
  576.  
  577.     // Third.  Assign columns based on ratios.
  578.     for ( i=0; i < columns; i++) {
  579.         j = ColInfo[i].total;
  580.         D1(printf("Aproximate column width = %d\n",(j * 1000) / whatif2));
  581.         ColInfo[i].col_temp = ((j * 1000) / whatif2);
  582.         ColInfo[i].col_width= 0;
  583.     }
  584.  
  585.     // Fourth.  Evaluate results against rules and assign hard values
  586.     for ( i=0; i < columns; i++) {
  587.         j = ColInfo[i].col_temp;
  588.  
  589.         // If assigned column was too small, hard assign minimum width
  590.         if ( j < ColInfo[i].maxword )
  591.                 ColInfo[i].col_width=ColInfo[i].maxword;
  592.  
  593.         // If assigned column larger than longest line, trim to minimum
  594.         if ( j > ColInfo[i].maxline )
  595.                 ColInfo[i].col_width=ColInfo[i].maxline;
  596.  
  597.         D1(printf("Hard-set column width = %d\n",ColInfo[i].col_width));
  598.     }
  599.  
  600.     // Fifth, add up text in columns which don't yet have a fixed size,
  601.     //  and number of already-assigned columns.
  602.     whatif  = 0;
  603.     whatif2 = 0;
  604.     for ( i=0; i < columns; i++ ) {
  605.         if ( ColInfo[i].col_width )
  606.             whatif2 += ColInfo[i].col_width;
  607.         else
  608.             whatif  += ColInfo[i].total;
  609.     }
  610.     D1(printf("After fixed assignments: %d total, %d preassigned\n",whatif,whatif2));
  611.  
  612.  
  613.     // Second, calculate ratios.  More text means larger column.
  614.     whatif  *= 1000;                   // Total chars in unassigned columns
  615.     whatif2  = whatif  / (columnspace-whatif2);    // Space avail
  616.  
  617.     // Third.  Assign columns based on ratios.
  618.     for ( i=0; i < columns; i++) {
  619.         j = ColInfo[i].total;
  620.         if ( 0==ColInfo[i].col_width) {
  621.             D1(printf("Col %d new aprox. width = %d\n",i,(j * 1000) / whatif2));
  622.             ColInfo[i].col_width = ((j * 1000) / whatif2);
  623.         }
  624.     }
  625.  
  626.     //
  627.     // !!! :TODO: Readjust plus or minus to fix any rounding errors
  628.     // in total assignment.
  629.     //
  630.     j = TABLE_INDENT;
  631.     for ( i=0; i< columns; i++) {
  632.         ColInfo[i].col_start = j;
  633.         j = j + 3 + ColInfo[i].col_width;
  634.     }
  635.     D1(printf("ThinkDeeply chooses: Complex fit\n"));
  636.     return(TABLE_INDENT);
  637. }
  638.  
  639.  
  640.  
  641.  
  642. /*
  643. **      Dump a ColumnInfo structure.
  644. */
  645. PrintCI(int x)
  646. {
  647. printf("## %02d First=%02d Word=%02d Line=%04d Total=%04d Lines=%02d/Start=%02d Width=%02d Wrap=%lx\n",
  648. x,ColInfo[x].maxfirst,ColInfo[x].maxword,ColInfo[x].maxline,ColInfo[x].total,
  649. ColInfo[x].tablelines,ColInfo[x].col_start,ColInfo[x].col_width,
  650. ColInfo[x].wrappointer);
  651. }
  652.  
  653. /*
  654. **      Write table. Given:
  655. **              Columns
  656. **              Information for each column
  657. **              Formatting-stripped, comma separated entries
  658. */
  659. WriteTable(int columns,char *table)
  660. {
  661. short   flag;
  662. short   cl_width,cl_start;
  663. int     i,j;
  664.  
  665. char *  start;
  666. char *  current;
  667. char *  lastword;       // End of last word encountered (for word wrap).
  668. char *  temp;
  669. char    rulechar='=';   // Character used for thick horizontal ruling lines
  670.  
  671. short   leftmargin;
  672.  
  673.  
  674.     leftmargin = ThinkDeeply(columns);
  675.  
  676.  
  677.     D1(for ( i=0; i< columns; i++))
  678.         D1(PrintCI(i));
  679.     D1(printf("^^ Final statistics for table ending at line %d ^^\n",ErrorLine(startinp,inp)));
  680.  
  681.     unless( leftmargin ) {
  682.         printf("Error: ThinkDeeply() could not resolve table (%d)\n",ErrorLine(startinp,inp));
  683.         return(0);
  684.     }
  685.  
  686.     while( *table )
  687.         {
  688.         // Position wrappointer at start of each column (just past ',')
  689.         temp = table;
  690.         for ( i=0; i< columns; i++) {
  691.             ColInfo[i].wrappointer = temp;
  692.             while( *temp && (*temp != DC1) && (*temp != LF) )
  693.                 temp++;
  694.             temp++;
  695.         }
  696.         temp--;
  697.         if ( *temp != LF )
  698.             printf("Warning: column count mismatch!\n");
  699.  
  700. #ifdef  NDEF
  701.         for ( i=0; i< columns; i++) {
  702.             printf("Col %d=%lx,%c%c\t",i,ColInfo[i].wrappointer,*(ColInfo[i].wrappointer),*(ColInfo[i].wrappointer+1));
  703.         }
  704.         printf("\n");
  705. #endif
  706.  
  707.         flag    =1;     // Zero when all columns have flowed all text
  708.         while( flag ) {
  709.             for(i=0; i<LINE_WIDTH+15; i++)
  710.                 outbuf[i]=' ';
  711.  
  712.             for ( i=0; i< columns; i++) {
  713.                 lastword = NULL;
  714.                 cl_width=ColInfo[i].col_width;
  715.                 cl_start=ColInfo[i].col_start;
  716.                 if ( i != columns-1 )   // Except for last column
  717.                         outbuf[cl_width+cl_start+1]=':';
  718.                 if ( start=current=ColInfo[i].wrappointer ) {
  719.                     while( *current==' ' || *current=='\t' || *current==DC2 )
  720.                         start++, current++;
  721.                     int noDC2seen = 1;
  722.                     while( *current ) {
  723.                         if ( *current == ' ' || *current == '\t' || *current == DC1 || *current == LF || *current == DC2 )
  724.                             if ( current-start <= cl_width )
  725.                                 if ( noDC2seen ) {
  726.                                         lastword = current; // Last full word
  727.                                         if( *current == DC2 )
  728.                                                 noDC2seen = 0;
  729.                                         }
  730.                         if ( *current == DC1 || *current == LF ) {
  731.                             if (lastword && (lastword-start)) {
  732.                                 memcpy(&outbuf[cl_start],start,lastword-start);
  733.                                 }
  734.                             if ( lastword == current)
  735.                                 ColInfo[i].wrappointer = NULL;
  736.                             else
  737.                                 ColInfo[i].wrappointer = lastword;
  738.                             break;
  739.                         }
  740.                         current++;
  741.                     }
  742.                 }
  743.             }
  744.  
  745.             outbuf[LINE_WIDTH+14]=0;
  746.             fprintf(outfile,"%s\n",outbuf);
  747.  
  748.             flag =0;
  749.             for ( i=0; i< columns; i++)
  750.                 if (ColInfo[i].wrappointer)
  751.                         flag=1;
  752.         }
  753.  
  754.         /*
  755.         **      Print middle ruling lines
  756.         */
  757.         if( !hasheader )
  758.                 rulechar='-';   // Switch immediatly to thin lines
  759.  
  760.         for(i=0; i<LINE_WIDTH; i++)
  761.             outbuf[i]=' ';
  762.         for ( i=0; i< columns; i++) {
  763.             cl_width=ColInfo[i].col_width;
  764.             cl_start=ColInfo[i].col_start;
  765.  
  766.             for( j=cl_start; j < cl_start+cl_width+1; j++)
  767.                 outbuf[j]=rulechar;
  768.             outbuf[j]=0;
  769.             if ( i != columns-1 )
  770.                 outbuf[j]='+', outbuf[j+1]=rulechar;
  771.         }
  772.         fprintf(outfile,"%s\n",outbuf);
  773.         rulechar='-';   // Switch immediatly to thin lines
  774.  
  775.         while( *table && *table != LF)    // Skip to next line
  776.             table++;
  777.         table++;
  778.         }
  779.         fprintf(outfile,"\n");
  780. }
  781.  
  782. /*
  783. **      Scan table, counting colums and gathering statistics.  Assumes
  784. **      all formatting codes have been stripped.
  785. **
  786. **      Count number of columns.  For each column, record:
  787. **              Max first word.
  788. **              Max word.
  789. **              Max line.
  790. **              Total characters.
  791. */
  792. int PrescanTable(char *table)
  793. {
  794. short cnt_chars=0;      // Running total of characters on line
  795. short cnt_wordchars=0;  // Running count of current word
  796.  
  797. short cnt_columns=0;    // Count of columns on current line
  798. short tot_columns=0;    // Check point.  Do all lines have same # columns?
  799.  
  800. short cnt_firstword=0;  // Size of first word, copied to ColInfo
  801. short cnt_maxword=0;    // Size of max word, copid to ColInfo
  802. int   i;
  803.  
  804.     for ( i=0; i < MAXCOLUMNS; i++) {
  805.         clrmem( ColInfo, sizeof(ColInfo) );
  806.     }
  807.  
  808.     while( *table )
  809.         {
  810.         switch ( *table )
  811.             {
  812.             case ' ':                           // (Note dupe in next case)
  813.             case DC2:
  814.                 if( !cnt_firstword )
  815.                     cnt_firstword = cnt_chars;   // Length of first word
  816.                 if( cnt_wordchars > cnt_maxword )
  817.                     cnt_maxword = cnt_wordchars; // Length of largest word
  818.  
  819.                 cnt_chars++;
  820.                 cnt_wordchars=0;
  821.                 break;
  822.             case DC1:
  823.             case LF:
  824.                 if( !cnt_firstword )
  825.                     cnt_firstword = cnt_chars;   // Length of first word
  826.                 if( cnt_wordchars > cnt_maxword )
  827.                     cnt_maxword = cnt_wordchars; // Length of largest word
  828.  
  829.                 if (ColInfo[cnt_columns].maxfirst < cnt_firstword)
  830.                     ColInfo[cnt_columns].maxfirst = cnt_firstword;
  831.                 if (ColInfo[cnt_columns].maxline  < cnt_chars)
  832.                     ColInfo[cnt_columns].maxline  = cnt_chars;
  833.                 if (ColInfo[cnt_columns].maxword  < cnt_maxword)
  834.                     ColInfo[cnt_columns].maxword  = cnt_maxword;
  835.                 ColInfo[cnt_columns].total       += cnt_chars;
  836.                 ColInfo[cnt_columns].tablelines  += 1;
  837.  
  838.                 cnt_columns++;                  // Move to next column
  839.                 if ( *table == LF)
  840.                 {
  841.                     if ( tot_columns )
  842.                         if ( cnt_columns != tot_columns)
  843.                             printf("Error: Column count mismatch %d != %d (%d)\n",
  844.                                    tot_columns, cnt_columns, ErrorLine(startinp,inp));
  845.                     tot_columns   =cnt_columns;
  846.                     if ( tot_columns > MAXCOLUMNS-1 )
  847.                         printf("Error: Too many columns! (%d)\n", ErrorLine(startinp,inp));
  848.                     cnt_columns   =0;
  849.                 }
  850.  
  851.                 cnt_firstword =0;
  852.                 cnt_maxword   =0;
  853.                 cnt_chars     =0;
  854.                 cnt_wordchars =0;
  855.                 break;
  856.             default:
  857.                 cnt_chars++;
  858.                 cnt_wordchars++;
  859.             }
  860.             table++;
  861.         }
  862.  
  863.         return( tot_columns );
  864. }
  865.  
  866. /*
  867. **      Strip off all table junk to product comma separated list.
  868. **      Record if a table heading (@Z_TBL_HEAD) was seen.
  869. */
  870. int CollectTable()
  871. {
  872. int     i=0;
  873.  
  874.  hasheader=0;
  875.  
  876. while( *inp )
  877. {
  878.  
  879.     while (*inp == LF)
  880.         inp++;
  881.  
  882.     if ( *inp == '@' )
  883.     {
  884.         if ( 0 == strncmp(inp, "@Z_TBL_END", 10) )
  885.         {
  886.             D1(printf("TBL_END\n"));
  887.             while( *inp && !(inp[0]==LF && inp[1]==LF) )
  888.                 inp++;
  889.             break;
  890.         }
  891.         if ( 0 == strncmp(inp, "@Z_TBL_HEAD", 10) )
  892.         {
  893.             D1(printf("TBL_TBL_HEAD\n"));
  894.             hasheader=1;
  895.         }
  896.         while (*inp && *inp != LF)      // Skip @ command
  897.             inp++;
  898.     } else {
  899.         while( *inp )
  900.         {
  901.             if ( i > (MAX_PARAGRAPH-100) ) {
  902.                 printf("Error: Paragraph too large!\n");
  903.                 break;
  904.             }
  905.  
  906.             /*  Escape ++, -- and ,,.  What a spitwad.
  907.             **  Does not handle joined columns "+," and "^,"
  908.             */
  909.             if      ( inp[0] == LF  &&  inp[1] == LF  ) {
  910.                 formatbuf[i++]= LF,     inp+=2;
  911.                 break;
  912.             }
  913.             else if ( inp[0] == '+' &&  inp[1] == '+' )
  914.                 formatbuf[i++] ='+',    inp++;
  915.             else if ( inp[0] == '^' &&  inp[1] == '^' )
  916.                 formatbuf[i++]= '^',    inp++;
  917.             else if ( inp[0] == '<' &&  inp[1] == '<' )
  918.                 formatbuf[i++]= '<',    inp++;
  919.             else if ( inp[0] == '>' &&  inp[1] == '>' )
  920.                 formatbuf[i++]= '>',    inp++;
  921.             else if ( inp[0] == '<' &&  inp[1] == 'R' && inp[2] == '>' )
  922.                 formatbuf[i++]= DC2,    inp+=3;
  923.             else if ( inp[0] == ',' &&  inp[1] == ',' )
  924.                 formatbuf[i++]= ',',    inp++;
  925.             else if ( inp[0] == ',' &&  inp[1] == ' ' )
  926.                 formatbuf[i++]= DC1,    inp++;
  927.             else if ( inp[0] == ',' )
  928.                 formatbuf[i++]= DC1;
  929.             else if ( inp[0] == LF )
  930.                 formatbuf[i++]= ' ';
  931.             else if ( inp[0] == '<' )
  932.         {
  933.          short nest=1;
  934.                    while( *inp++ && nest )
  935.             {
  936.             switch( *inp )
  937.             {
  938.             case '>':
  939.                 nest--;
  940.                 break;
  941.             case '<':
  942.                 nest++;
  943.             default:
  944.             }
  945.             }
  946.             inp--;
  947.                 }
  948.             else
  949.                 formatbuf[i++]=*inp;
  950.             inp++;
  951.         }
  952.     }
  953. }
  954. formatbuf[i]=0;
  955. formatbuf[i+1]=0;
  956. formatbuf[i+2]=0;
  957. formatbuf[i+3]=0;
  958. return(i);
  959. }
  960.  
  961. int CollectParagraph()
  962. {
  963. int     i=0;
  964.  
  965.     while( *inp )
  966.         {
  967.         if ( (*inp==LF) && (*(inp+1)==LF) )     // Two LF's signal end of para
  968.                 break;
  969.  
  970.         if ( *inp==CR ) {
  971.             printf("Error: File must not contain CR's\n");
  972.             break;
  973.             }
  974.  
  975.         if ( i > (MAX_PARAGRAPH-100) ) {
  976.             printf("Error: Paragraph too large!\n");
  977.             break;
  978.             }
  979.  
  980.         //      Escape double <<brackets>>. Skip single <brackets>
  981.         //
  982.         if      ( inp[0] == '<' && inp[1] == '<' )
  983.                 formatbuf[i++]='<',inp += 2;
  984.         else if ( inp[0] == '>' && inp[1] == '>' )
  985.                 formatbuf[i++]='>',inp += 2;
  986.         else if ( inp[0] == '<' ) {
  987.                 if ( inp[1]=='R' && inp[2]=='>' ) // Convert <R> to LF
  988.                         {
  989.                         formatbuf[i++]=LF;
  990.                         if ( inp[3] == '\n' )
  991.                                 inp++;
  992.                         inp += 3;
  993.                         }
  994.                 else if ( inp[1]=='N' && inp[2]=='>' ) // Convert <N> to ` `
  995.                         {
  996.                         formatbuf[i++]=' ';
  997.                         if ( inp[3] == '\n' )
  998.                                 inp++;
  999.                         inp += 3;
  1000.                         }
  1001.                 else if ( inp[1]=='$' && inp[2]=='R' )
  1002.                         {
  1003.                     while( *inp && *inp++ != ']' )
  1004.                 ;
  1005.             if( *inp == '>')
  1006.                     printf("Warning: No chapter number in Cross-Ref (%d)\n",ErrorLine(startinp,inp));
  1007.             while( *inp && (*inp != '>') ) {
  1008.                 formatbuf[i++] = *inp;
  1009.                 inp++;
  1010.                 }
  1011.             inp++;
  1012.             }
  1013.                 else    {
  1014.              short nest=1;
  1015.             inp++;
  1016.                     while( *inp && nest )
  1017.                 {
  1018.                 switch( *inp )
  1019.                 {
  1020.                 case '>':
  1021.                     nest--;
  1022.                     break;
  1023.                 case '<':
  1024.                     nest++;
  1025.                 default:
  1026.                 }
  1027.                         inp++;
  1028.                 }
  1029.             }
  1030.                 }
  1031.     /*
  1032.     **    Ventura seems to put a space at the end of lines, but also
  1033.     **    accept files without the space.  As a guess, I force a single
  1034.     **    space to the end of the line if none, else accept any number
  1035.     **    of spaces found there.
  1036.     */
  1037.         else if ( *inp == LF ) {
  1038.         if(!( formatbuf[i-1]==' ' ))
  1039.                     formatbuf[i++]=' ';
  1040.         inp++;
  1041.         }
  1042.         else
  1043.                 formatbuf[i++]=*inp,inp++;
  1044.         }
  1045.     formatbuf[i]=0;
  1046.     formatbuf[i+1]=0;
  1047.     formatbuf[i+2]=0;
  1048.     formatbuf[i+3]=0;
  1049.  
  1050.     return(i);
  1051. }
  1052.  
  1053. void FormatParagraph(int slen,char *prestring1,char *prestring2)
  1054. {
  1055. int     pass=0;
  1056. int     pos=0;
  1057. int     scan=0;
  1058. int     perline= LINE_WIDTH + 1 - strlen(prestring1) - indent;
  1059. int     i;
  1060.  
  1061.     D2(printf("FormatParagraph. Slen=%d, pre1=%s,pre2=%s\n", slen, prestring1,prestring2));
  1062.     D2(printf("%s", formatbuf));
  1063.  
  1064.     // Process normal text paragraph.  Wrap words, nuke spaces at start
  1065.     // of line, etc.  Handle <R>, grumble.
  1066.     while ( pos < slen )
  1067.         {
  1068.  
  1069.         // If there is a newline within the current line range, pump out
  1070.         // that string.  Else set scan to just past end of line (or EOF)
  1071.         // and work backwards to word-wrap.
  1072.         scan=0;
  1073.         for (i=0; i < perline; i++)
  1074.                 {
  1075.                 if ( !formatbuf[pos+i] )
  1076.                         break;
  1077.                 if ( formatbuf[pos+i] == '\n' )
  1078.                         {
  1079.                         scan = pos+i+1; // Include linefeed
  1080.                         D(printf("Newline found at %d\n",i));
  1081.                         break;
  1082.                         }
  1083.                 }
  1084.  
  1085.         if( !scan )
  1086.                 {
  1087.                 // Skip leading spaces
  1088.                 while ( formatbuf[pos]==' ' || formatbuf[pos]=='\t' )
  1089.                         pos++;
  1090.                 if ( pos >= slen )
  1091.                         break;
  1092.  
  1093.                 scan = pos + perline;   // Just past end of line
  1094.  
  1095.                 if ( scan > slen)
  1096.                         scan = slen;    // Set to EOF
  1097.  
  1098.                 // Scan backwards for NULL, LF, space separator or start of line
  1099.                 while( scan > pos && formatbuf[scan] && formatbuf[scan] != ' ' && formatbuf[scan] != '\t' )
  1100.                         scan--;
  1101.  
  1102.                 D(printf("Word-wrapped to %d bytes\n",scan-pos));
  1103.  
  1104.                 if (pos == scan)
  1105.                         printf("ERROR: Huge word (near line %d)\n",ErrorLine(startinp,inp));
  1106.                 }
  1107.  
  1108.         if ( indenttextvalid )
  1109.                 fwrite(indenttext,indent,1,outfile), indenttextvalid=0;
  1110.         else
  1111.                 fwrite(allspaces,indent,1,outfile);
  1112.  
  1113.         if ( pass )
  1114.                 fprintf(outfile,prestring2);
  1115.         else
  1116.                 fprintf(outfile,prestring1);
  1117.  
  1118.         fwrite(&formatbuf[pos],scan-pos,1,outfile);
  1119.         if ( formatbuf[scan-1] != '\n' )
  1120.                 fprintf(outfile,"\n");
  1121.  
  1122.         pos = scan;
  1123.         pass++;
  1124.         }
  1125.     fprintf(outfile,"\n");
  1126. }
  1127.  
  1128.  
  1129. /*******************************************************************************
  1130. **      @ Function tables & flags
  1131. */
  1132. #define ATSKIP          4       // Longs per atstuff entry
  1133.  
  1134. #define AF_OPT          0x0001  // Option indenting
  1135. #define AF_BODY         0x0002  // Body indenting
  1136. #define AF_NOFLUSH      0x0004  // Disable flush before next @COMMAND
  1137. #define AF_ENUM         0x0008  // Don't reset enum_val
  1138. #define AF_INDENTOK     0x0010  // For @ command, indent text is ok.
  1139.  
  1140. // SNAME is like NAME, but should have no space above.  We can't do
  1141. // this, however :-).
  1142. void *(*atstuff[])()={
  1143. "@NAME",                NAME,           AF_BODY,        BODY_INDENT,
  1144. "@SNAME",               NAME,           AF_BODY,        BODY_INDENT,
  1145. "@OPTION",              OPTION,         AF_OPT,         OPTION_INDENT,
  1146. "@INPUTV",              VFORMAT,        AF_BODY,        BODY_INDENT,
  1147. "@RESULTV",             VFORMAT,        AF_BODY,        BODY_INDENT,
  1148. "@INPUTD",              GENERIC,        AF_INDENTOK,    D_INDENT,
  1149. "@RESULTD",             GENERIC,        AF_INDENTOK,    D_INDENT,
  1150. "@MINOR HEADING",       MINOR_HEADING,  AF_BODY,        BODY_INDENT,
  1151. "@MAJOR HEADING",       MAJOR_HEADING,  AF_BODY,        BODY_INDENT,
  1152. "@CATEGORY",            CATEGORY,       AF_BODY,        BODY_INDENT,
  1153. "@BULLET",              BULLET,         AF_BODY,        BODY_INDENT,
  1154. "@BEGINNER",            BEGINNER,       AF_BODY,        0,
  1155. "@NOTE",                NOTE,           AF_BODY,        0,
  1156. "@WARNING",             WARNING,        AF_BODY,        0,
  1157. "@VERBATIM",            GENERIC,        AF_BODY,        0,
  1158. "@FUNCTION",            GENERIC,        AF_BODY,        BODY_INDENT,
  1159. "@LIBRARY",             GENERIC,        AF_BODY,        BODY_INDENT,
  1160. "@SYNTAX",              GENERIC,        AF_BODY,        BODY_INDENT,
  1161. "@INPUTS",              GENERIC,        AF_BODY,        BODY_INDENT,
  1162. "@RESULTS",             GENERIC,        AF_BODY,        BODY_INDENT,
  1163. "@DESCRIPTION",         GENERIC,        AF_BODY,        BODY_INDENT,
  1164. "@AME_BODY",            GENERIC,        AF_BODY,        BODY_INDENT,
  1165. "@EXAMPLE_LIB",         EXAMPLE,        AF_OPT,         0,
  1166. "@EXAMPLE",             EXAMPLE,        AF_OPT,         0,
  1167. "@WIDEEXAMPLE",         EXAMPLE,        AF_OPT,         0,
  1168. "@SEE ALSO",            GENERIC,        AF_BODY,        BODY_INDENT,
  1169. "@ENUM",                ENUM,           AF_ENUM,        BODY_INDENT,
  1170. "@Z_TBL_BEG",           Z_TBL_BEG,      AF_BODY,        0,
  1171. "@Body Text",           GENERIC,        AF_BODY,        BODY_INDENT,
  1172. 0,                      0,              0,              BODY_INDENT,
  1173. };
  1174.  
  1175. #ifdef  NOTDEF
  1176. struct STRINGS partypes[] = {
  1177.    { 0, "CHAPTER HEAD",    NULL         },
  1178.    { 0, "INPUTV",          NULL         },
  1179.    { 0, "INPUTD",          NULL         },
  1180.    { 0, "Z_TBL_BEG",       NULL         },
  1181.    { 0, "Z_TBL_BODY",      NULL         },
  1182.    { 0, "Z_TBL_HEAD",      NULL         },
  1183.    { 0, "Z_TBL_END",       NULL         },
  1184.    { 0, "STEP2",           NULL         },
  1185.    { 0, "PARAFILTER ON",   NULL         },
  1186.    { 0, "ERRMESS",         NULL         },
  1187.    { 0, "INDEN1",          NULL         },
  1188.    { 0, "INDEN2",          NULL         },
  1189.    { 0, "INDEN2M",         NULL         },
  1190.    { 0, "INDEN2B",         NULL         },
  1191.    { 0, "INDENT",          NULL         },
  1192.    { 0, "INDEN2MID",       NULL         },
  1193.    { 0, "INDEN1MID",       NULL         },
  1194.    { 0, "INDEN1BOT",       NULL         },
  1195.    { 0, "INDEN2BOT",       NULL         },
  1196.    { 0, "LISTCAP",         NULL         },
  1197.    { 0, "LISTBODY",        NULL         },
  1198.    { 0, "CAPTION",         NULL         },
  1199.    { 0, "DEFINES",         NULL         },
  1200.    { 0, "TBL TITLE",       NULL         },
  1201. };
  1202. #endif
  1203.  
  1204. /*******************************************************************************
  1205. **      Processfile.  Until reaching a null, scan the input file for
  1206. **      @XXX keywords.  Executue @ function, or print warning and keep
  1207. **      scanning.
  1208. */
  1209. void ProcessFile()
  1210. {
  1211. int     j;
  1212. int     atindex;
  1213. //      char    *temp;  DICE BUG
  1214.  
  1215.     D(printf("ProccessFile: outfile=%lx, inp=%lx\n",outfile,inp));
  1216.  
  1217.     while( *inp )
  1218.         {
  1219.         if (*inp == LF)
  1220.             *inp++;
  1221.         else if (*inp == CR)
  1222.             {
  1223.             printf("Error: File must not contain CR's\n");
  1224.             break;
  1225.             }
  1226.         else if (*inp == '@')
  1227.             {
  1228.             /*
  1229.             **  Find matching @ command
  1230.             */
  1231.             for( atindex=0; atstuff[atindex]; atindex += ATSKIP)
  1232.                 {
  1233.                 if( !strncmp(atstuff[atindex], inp, strlen(atstuff[atindex])) )
  1234.                     break;
  1235.                 }
  1236.  
  1237.             /*
  1238.             **  Execute @ command, if any.  Else flush any pending line.
  1239.             */
  1240.             if( !atstuff[atindex] )
  1241.                 {
  1242.                 printf("Warning: Unmatched tag: "),putn(inp,'='),printf("\n");
  1243.  
  1244.                 // Skip to next signifcant thing
  1245.                 inp++;
  1246.                 while( *inp && !(*inp=='@') && !(inp[0]==LF && inp[1]==LF) )
  1247.                     inp++;
  1248.                 }
  1249.             else{
  1250.                 D2( printf("Matched tag: %s\n",atstuff[atindex]) );
  1251.  
  1252.                 while( *inp && !(*inp=='=') )   // Skip to '='
  1253.                     inp++;
  1254.                 unless( inp[1]==' ' && inp[2])
  1255.                         {
  1256.                         D3(printf("Warning: nothing after @ tag (%d)\n",ErrorLine(startinp,inp)));
  1257.                         while( *inp && !(*inp=='@') && !(inp[0]==LF && inp[1]==LF) )
  1258.                                inp++;
  1259.                         }
  1260.                 else    {
  1261.                         inp += 2;
  1262.  
  1263.                         unless( ((int)atstuff[atindex+2]) & AF_ENUM )
  1264.                                 enum_val = 1;   // Reset ENUM count
  1265.  
  1266.                         if( atstuff[atindex+3] )
  1267.                             indent = (int)atstuff[atindex+3];
  1268.  
  1269.                         unless( ((int)atstuff[atindex+2]) & AF_INDENTOK ) {
  1270.                                 if( indenttextvalid == INDENT_OPTION ) {
  1271.                                     printf("Warning: Left margin text lost (%d)\n", ErrorLine(startinp,inp));
  1272.                                     printf("Warning: Text lost was \"%s\"\n", indenttext);
  1273.                                     }
  1274.                                 else if( indenttextvalid == INDENT_VFORMAT )
  1275.                                     fprintf(outfile,"%s\n\n",indenttext);
  1276.  
  1277.                                 for( j=0; j<LINE_WIDTH+2; j++)
  1278.                                         outbuf[j]=' ';
  1279.                                 outbuf[j+1]=0;
  1280.  
  1281.                                 indenttextvalid =0;
  1282.                         }
  1283.  
  1284.                         (*atstuff[atindex+1])(inp);
  1285.                         }
  1286.                 }
  1287.             }
  1288.         else{
  1289.             enum_val = 1;       // Body text resets ENUM to base
  1290.  
  1291.             FormatParagraph(CollectParagraph(),"","");
  1292.             }
  1293.         }
  1294.     D(printf("End ProccessFile: outfile=%lx, inp=%lx\n",outfile,inp));
  1295. }
  1296.